package cn.gs.util.monitor;

// @author gs
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

public class TimerMonitor extends Thread {

    private DelayQueue<Task> queue;

    public TimerMonitor() {
        queue = new DelayQueue();
        this.start();
    }

    public TimerMonitor(String name) {
        super(name);
        queue = new DelayQueue();
        this.start();
    }

    public void add(ITimerMonitorTask task, int timeout, int retry) {
        Task t = new Task();
        t.task = task;
        t.leftErrorCount = retry;
        t.timeout = TimeUnit.MILLISECONDS.convert(timeout, TimeUnit.SECONDS);
        t.endtime = System.currentTimeMillis() + t.timeout;
        queue.offer(t);
        task.start();
    }

    @Override
    public void run() {
        Logger.getLogger(TimerMonitor.class.getName()).log(Level.INFO, "TimerMoniter_{0}_Start", this.getName());
        try {
            while (true) {
                Task task = queue.take();
                if (task.leftErrorCount > 0) {
                    --task.leftErrorCount;
                    task.endtime = System.currentTimeMillis() + task.timeout;
                    try {
                        boolean b = task.task.retry();
                        if (!b) {
                            queue.add(task);
                        }
                    } catch (Throwable ex) {
                        Logger.getLogger(TimerMonitor.class.getName()).log(Level.WARNING, "TimerMoniter_" + this.getName() + "_task_retry_error_" + task.leftErrorCount + "_left", ex);
                        queue.add(task);
                    }

                } else {
                    try {
                        task.task.fail();
                    } catch (Throwable ex) {
                        Logger.getLogger(TimerMonitor.class.getName()).log(Level.WARNING, "TimerMoniter_" + this.getName() + "_task_error", ex);
                    }
                }
            }
        } catch (InterruptedException ex) {
            Logger.getLogger(TimerMonitor.class.getName()).log(Level.SEVERE, "TimerMoniter_" + this.hashCode() + "_Interrupted", ex);
        }
        Logger.getLogger(TimerMonitor.class.getName()).log(Level.SEVERE, "TimerMoniter_{0}_Start", this.hashCode());
    }

    private class Task implements Delayed {

        ITimerMonitorTask task;
        private long endtime, timeout;
        private int leftErrorCount;

        @Override
        public long getDelay(TimeUnit unit) {
            return unit.convert(endtime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
        }

        @Override
        public int compareTo(Delayed o) {
            Task that = (Task) o;
            return endtime > that.endtime ? 1 : (endtime < that.endtime ? -1 : 0);
        }
    }
}
